#include <EB0/EB0.h>

namespace EB0
{
namespace Managers
{
	// Static Member
	TaskManager* TaskManager::mSingleton = 0;

#pragma region Constructor / Destructor
	// Constructor
	TaskManager::TaskManager()
	{
		// Default values
		mDirtyTaskSet = false;
	}

	// Destructor
	TaskManager::~TaskManager()
	{
		// Remove all tasks
		removeAllTasks();

		// Reset values
		mDirtyTaskSet = false;
		mSingleton = 0;
	}
#pragma endregion

#pragma region Singleton
	// Singleton Reference
	TaskManager& TaskManager::getSingleton()
	{
		return *getSingletonPtr();
	}

	// Singleton Pointer
	TaskManager* TaskManager::getSingletonPtr()
	{
		if (!mSingleton) mSingleton = new TaskManager();
		return mSingleton;
	}
#pragma endregion

#pragma region Update Tasks
	// Update Tasks
	void TaskManager::update(float dt)
	{
		// Lock mutex; automatically unlocks when the function terminates
		sf::Lock lock(mMutex);

		// Perform update() on all tasks
		mDirtyTaskSet = false; // only necessary during traversal

		// Traverse each window listener calling the appropriate event
		static GameTaskSet::iterator gameTaskIter; // frequently created otherwise, for traversing
		static GameTaskSet completedTasks; // set of completed tasks, for additional checking on dirty sets
		static bool dirtyTaskFlag = false; // we need only check the completedTasks list when the set has been dirtied

		if (!mTasks.empty())
		{
			gameTaskIter = mTasks.begin();
			completedTasks.clear(); // clear the array of called tasks
			dirtyTaskFlag = false; // no need to do the extra checking... yet

			while (gameTaskIter != mTasks.end())
			{
				// Has this task already been called?
				if (dirtyTaskFlag && completedTasks.find(*gameTaskIter) != completedTasks.end())
				{
					// Skip it
					gameTaskIter++;
					continue;
				}

				// Add the task to the already completed list
				completedTasks.insert(*gameTaskIter);

				// Call update()
				(*gameTaskIter)->update(dt);

				// Has the tasks set been altered?
				if (mDirtyTaskSet)
				{
					// Go to the beginning of the list if there are still tasks
					if (!mTasks.empty())
						gameTaskIter = mTasks.begin();

					// Reset the flag as the situation is now being taken care of
					mDirtyTaskSet = false;
					dirtyTaskFlag = true; // we'll need to perform additional checking now...
				}
				else
					gameTaskIter++;
			}
		}
	}
#pragma endregion

#pragma region Task Management
	// Add Task
	void TaskManager::addTask(Tasks::GameTask* gameTask)
	{
		// Lock mutex; automatically unlocks when the function terminates
		sf::Lock lock(mMutex);

		// Abort on bad pointer
		if (!gameTask) return;

		// Start the task
		gameTask->start();

		// Add the task
		mTasks.insert(gameTask);
		mDirtyTaskSet = true;
	}

	// Remove Task
	void TaskManager::removeTask(Tasks::GameTask* gameTask)
	{
		// Lock mutex; automatically unlocks when the function terminates
		sf::Lock lock(mMutex);

		// Abort on bad pointer
		if (!gameTask) return;

		// Stop the task
		gameTask->stop();

		// Remove the task
		mTasks.erase(gameTask);
		mDirtyTaskSet = true;
	}

	// Remove All Tasks
	void TaskManager::removeAllTasks()
	{
		// Lock mutex; automatically unlocks when the function terminates
		sf::Lock lock(mMutex);

		// Are there tasks to remove?
		if (!mTasks.empty())
		{
			// Traverse through all tasks and stop them
			for (GameTaskSet::iterator gameTaskIter = mTasks.begin(); gameTaskIter != mTasks.end(); gameTaskIter++)
				(*gameTaskIter)->stop();

			// Set the dirty flag, in case this function was called through a task
			mDirtyTaskSet = true;

			// Clear out the set
			mTasks.clear();
		}
	}
#pragma endregion
} // namespace Managers
}